from keyword import iskeyword

from cn2an import cn2an
from .ply.lex import lex, Lexer

__all__ = ['get_lexer', 'tokens', 'reserved']

reserved = [
    '符合',
    '构造',
    '剩下',
    '的映射',
    '的序列',
    '匹配',
    '弃元',
    '到列表',
    '到集合',
    '到字典',
    '选取',
    '中的成员',
    '中',
    '对应',
    '持有',
    '如果失败',
    '接受',
    '的匿名函数',
    '导入所有',
    '前',
    '级',
    '级的',
    '之后为关键字参数',
    '之前为位置参数',
    '变长',
    '变长映射',
    '定义返回',
    '的函数',
    '有',
    '的列表',
    '的集合',
    '的元组',
    '的字典',
    '空列表',
    '空元组',
    '空集合',
    '空字典',
    '类型为',
    '类型的',
    '修饰',
    '赋值为',
    '更新',
    '开始',
    '最后',
    '的成员',
    '到',
    '每隔',
    '解包',
    '解包映射',
    '和',
    '矩阵乘法',
    '正',
    '负',
    '计算',
    '的值',
    '如果',
    '否则',
    '是',
    '不是',
    '在',
    '不在',
    '且',
    '或',
    '不',
    '赋值',
    '为',
    '以',
    '调用',
    '直接调用',
    '定义函数',
    '为参数',
    '以上',
    '当',
    '时',
    '对于',
    '中的每一个',
    '返回',
    '跳出',
    '重新',
    '产出',
    '尝试',
    '总之',
    '如果有异常',
    '捕获异常',
    '抛出',
    '声明',
    '为全局',
    '为非局部',
    '导入',
    '从',
    '断言',
    '异步',
    '等待',
    '删除',
    '的',
    '的第',
    '个',
    '大于',
    '小于',
    '大于等于',
    '小于等于',
    '等于',
    '不等于',
    '加',
    '减',
    '乘',
    '除',
    '整除',
    '取模',
    '乘方',
    '位和',
    '位或',
    '异或',
    '取反',
    '左移',
    '右移',
    '然后',
    '定义类',
    '派生自',
    '接着',
    '真',
    '假',
    '无',
    '没什么',
    '跳过'
]

tokens = [
    'INT',
    'FLOAT',
    'STR',
    'BSTR',
    'RSTR',
    'RBSTR',
    'ESTR',
    'NAME'
]
tokens.extend(reserved)

def get_lexer() -> Lexer:

    t_ignore = ' \t\n'

    def transform(s):
        return (s.replace('\\"', '"')
            .replace('\\t', '\t')
            .replace('\\n', '\n')
            .replace('\\a', '\a')
            .replace('\\b', '\b')
            .replace('\\f', '\f')
            .replace('\\r', '\r')
            .replace('\\v', '\v')
            .replace('\\0', '\0')
            .replace('\\\\', '\\')
            .replace('\\?', '?'))

    def t_COMMENT(t):
        r'注释.*'

    def t_ESTR(t):
        r'""'
        t.value = ''
        return t

    def t_STR(t):
        r'".*?[^\\]"'
        t.value = transform(t.value[1:-1])
        return t

    def t_BSTR(t):
        r'字节".*?[^\\]"'
        t.value = transform(t.value[3:-1]).encode()
        return t

    def t_RSTR(t):
        r'原始".*?[^\\]"'
        t.value = t.value[3:-1].replace('\\"', '"')

    def t_RBSTR(t):
        r'原始字节".*?[^\\]"'
        t.value = t.value[5:-1].replace('\\"', '"').encode()

    cndigits = '零一二三四五六七八九'
    cndigitsweights = '[' + cndigits + '十百千万亿]+'
    cndigits = '[' + cndigits + ']+'

    def t_FLOAT(t):
        int, decimal = t.value.split('点')
        t.value = cn2an(int) + cn2an(decimal, mode='normal') * 10 ** -len(decimal)
        return t

    def t_INT(t):
        t.value = cn2an(t.value)
        return t

    t_INT.__doc__ = cndigitsweights
    t_FLOAT.__doc__ = cndigitsweights + '点' + cndigits

    def t_NAME(t):
        r'\w+'
        if t.value in reserved:
            t.type = t.value
        if not t.value.isidentifier() or iskeyword(t.value):
            raise SyntaxError(f'非法标识符 {t.value}')
        return t

    def t_error(t):
        raise SyntaxError('无效字符 {!r}'.format(t.value[0]))

    return lex()
